package org.sanm.domain.order;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import org.sanm.domain.category.Category;
import org.sanm.domain.company.Company;
import org.sanm.domain.goods.Goods;
import org.sanm.domain.order.model.*;
import org.sanm.domain.project.Project;
import org.sanm.utils.RandomUtil;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final OrderMapper orderMapper;

    @Override
    public Order add(OrderReq orderReq) {
        Order order = Convert.convert(Order.class, orderReq);
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        order.setNo(RandomUtil.genMillAndRandomNo(10));
        long sum = orderReq.getOrderGoodsList().stream().mapToLong(item -> item.getGoodsPrice() * item.getGoodsNum()).sum();
        order.setAmount(sum);
        Project project = Db.getById(orderReq.getProjectId(), Project.class);
        order.setProjectName(project.getName());
        save(order);
        for(OrderGoods og : orderReq.getOrderGoodsList()){
            og.setOrderId(order.getId());
            Goods goods = Db.getById(og.getGoodsId(), Goods.class);
            Company company = Db.getById(goods.getCompanyId(), Company.class);
            Category category = Db.getById(goods.getCategoryId(), Category.class);
            og.setGoodsName(goods.getName());
            og.setGoodsUnit(goods.getUnit());
            og.setCompanyId(company.getId());
            og.setCompanyName(company.getName());
            og.setCategoryId(category.getId());
            og.setCategoryName(category.getName());
            Db.save(og);
        }
        return order;
    }

    @Override
    public void update(OrderReq orderReq) {
        Order order = Convert.convert(Order.class, orderReq);
        order.setUpdateTime(LocalDateTime.now());
        long sum = orderReq.getOrderGoodsList().stream().mapToLong(item -> item.getGoodsPrice() * item.getGoodsNum()).sum();
        order.setAmount(sum);
        Project project = Db.getById(orderReq.getProjectId(), Project.class);
        order.setProjectName(project.getName());
        updateById(order);
        Db.lambdaUpdate(OrderGoods.class).eq(OrderGoods::getOrderId, order.getId()).remove();
        for(OrderGoods og : orderReq.getOrderGoodsList()){
            og.setOrderId(order.getId());
            Goods goods = Db.getById(og.getGoodsId(), Goods.class);
            Company company = Db.getById(goods.getCompanyId(), Company.class);
            Category category = Db.getById(goods.getCategoryId(), Category.class);
            og.setGoodsName(goods.getName());
            og.setGoodsUnit(goods.getUnit());
            og.setCompanyId(company.getId());
            og.setCompanyName(company.getName());
            og.setCategoryId(category.getId());
            og.setCategoryName(category.getName());
            Db.save(og);
        }
    }

    @Override
    public OrderRes getDetail(Integer id) {
        Order order = getById(id);
        List<OrderGoods> orderGoodsList = Db.lambdaQuery(OrderGoods.class).eq(OrderGoods::getOrderId, id).list();
        List<Integer> goodsIds = orderGoodsList.stream().map(OrderGoods::getGoodsId).toList();
        List<Goods> goodsList = Db.lambdaQuery(Goods.class).in(Goods::getId, goodsIds).list();
        Map<Integer, OrderGoods> orderGoodsMap = orderGoodsList.stream().collect(Collectors.toMap(OrderGoods::getGoodsId, item -> item));

        List<Integer> companyIds = goodsList.stream().map(Goods::getCompanyId).toList();
        List<Company> companyList = Db.lambdaQuery(Company.class).in(Company::getId, companyIds).list();
        Map<Integer, Company> companyMap = companyList.stream().collect(Collectors.toMap(Company::getId, item -> item));

        for(Goods goods : goodsList){
            OrderGoods orderGoods = orderGoodsMap.get(goods.getId());
            goods.setPrice(orderGoods.getGoodsPrice());
            goods.setNum(orderGoods.getGoodsNum());
            goods.setCompany(companyMap.get(goods.getCompanyId()));
        }


        Project project = Db.getById(order.getProjectId(), Project.class);

        OrderRes orderRes = Convert.convert(OrderRes.class, order);
        orderRes.setGoodsList(goodsList);
        orderRes.setProject(project);
        return orderRes;
    }

    @Override
    public List<OrderRes> getByIds(List<Integer> ids) {
        List<Order> orderList = lambdaQuery().in(Order::getId, ids).list();
        List<Integer> orderIds = orderList.stream().map(Order::getId).toList();
        List<OrderGoods> orderGoodsList = Db.lambdaQuery(OrderGoods.class).in(OrderGoods::getOrderId, orderIds).list();
        // orderId ==> OrderGoods[]
        Map<Integer, List<OrderGoods>> orderGoodsMap = orderGoodsList.stream().collect(Collectors.groupingBy(OrderGoods::getOrderId));

        List<Integer> goodsIds = orderGoodsList.stream().map(OrderGoods::getGoodsId).toList();
        List<Goods> goodsList = Db.lambdaQuery(Goods.class).in(Goods::getId, goodsIds).list();
        // goodsId ==> Goods
        Map<Integer, Goods> goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getId, item -> item));

        List<Integer> companyIds = goodsList.stream().map(Goods::getCompanyId).toList();
        List<Company> companyList = Db.lambdaQuery(Company.class).in(Company::getId, companyIds).list();
        // companyId ==> Company
        Map<Integer, Company> companyMap = companyList.stream().collect(Collectors.toMap(Company::getId, item -> item));



        for(Goods goods : goodsList){

            goods.setCompany(companyMap.get(goods.getCompanyId()));
        }

        return null;
    }

    @Override
    public Page<OrderListRes> list(Integer pageNum,
                                   Integer pageSize,
                                   String no,
                                   String projectName,
                                   String goodsName,
                                   String companyName,
                                   String startDate,
                                   String endDate
                            ) {
        Page<OrderListRes> page = Page.of(pageNum, pageSize);

        Integer pageIndex = (pageNum - 1) * pageSize;
        List<OrderListRes> list = orderMapper.list(pageIndex, pageSize, no, projectName, goodsName, companyName, startDate, endDate);
        Integer count = orderMapper.count(pageIndex, pageSize, no, projectName, goodsName, companyName, startDate, endDate);
        page.setRecords(list);
        page.setTotal(count);


        return page;
    }


}
